
<template>
    <div class="app-container">
        <el-container style="margin-left: 16px; margin-bottom: 15px" >
            <el-autocomplete
                v-model="listQuery.user"
                :fetch-suggestions="querySearch"
                clearable
                class="d3"
                placeholder="查询用户 Search User"
                @select="handleSelect"
                :prefix-icon="iconSearch"
                @keyup.enter="handleFilter"
            />

            <el-input
                v-model="listQuery.cmd"
                class="d3"
                placeholder="查询操作 Search Command"
                :prefix-icon="iconSearch"
                @keyup.enter="handleFilter"/>

            <el-input
                v-model="listQuery.hash"
                class="d3"
                placeholder="查询哈希 Filter Hash"
                :prefix-icon="iconSearch"
                @keyup.enter="handleFilter"/>

            <div class="d3">
                <!-- <span class="demonstration">With shortcuts</span> -->
                <el-date-picker
                    v-model="dateRange"
                    type="datetimerange"
                    :shortcuts="datetimeShortcuts"
                    range-separator="-"
                    start-placeholder="开始时间"
                    end-placeholder="结束时间"
                />
            </div>

        </el-container>
        <!-- <span> <el-text tag="b" style="margin-right: 30px;"> User: </el-text> </span> -->

        <!-- <div class="filter-container" style="margin-left: 30px;"> -->
        <!-- <el-input v-model= placeholder="root" style="width: 200px;" class="filter-item" /> -->

        <!-- <el-checkbox v-model="listQuery.ascending" class="filter-item" style="margin-left:15px;" @change="handleFilter"> -->
        <!-- Ascending -->
        <!-- </el-checkbox> -->
        <!-- </div> -->

        <el-table :key="tableKey" v-loading="listLoading" :data="list"
                                  class="main-table"
                                  fit
                                  highlight-current-row
                                  style="width: 100%;"
                                  height="100%"
                                  :row-class-name="rowClassName"
                                  @sort-change="sortChange"
        >
            <!-- 🦜: we want: id,user,cmd,argv,time,chained, tx-hash -->

            <!-- 🦜 :here's more data -->
            <el-table-column type="expand">
                <template #default="props">
                    <!-- 🦜 : here show: txhash, registerTime, pid, ppid, fullCommand -->
                    <div class="d0">
                        <h3>详细信息 More Info:</h3>
                        <div style="padding-left: 30px;">
                            <el-row :gutter="20" class="d1">
                                <el-col :span="4"> <el-text type="info" tag="b"> 存证交易哈希 <TT>txHash</TT>: </el-text></el-col>
                                <!-- 🦜 : use tag="b" to make bold-->
                                <el-col :span="6"> <el-text type="info"> {{props.row.tx_hash}} </el-text></el-col>

                                <el-col :span="4"> <el-text type="info" tag="b"> 存证时间 <TT>registerTime</TT> : </el-text></el-col>
                                <el-col :span="6"> <el-text type="info"> {{parseTime(props.row.registerTime)}} </el-text></el-col>
                            </el-row>

                            <el-row :gutter="20" class="d1">
                                <el-col :span="4"> <el-text type="info" tag="b">
                                    <TT>pid</TT> :
                                </el-text></el-col>
                                <el-col :span="6"> <el-text type="info">
                                    {{props.row.pid}}
                                </el-text></el-col>

                                <el-col :span="4"> <el-text type="info" tag="b">
                                    <TT>ppid</TT> :
                                </el-text></el-col>
                                <el-col :span="6"> <el-text type="info">
                                    {{props.row.ppid}}
                                </el-text>
                                </el-col>
                            </el-row>

                            <el-row :gutter="20" class="d1">
                                <el-col :span="4"> <el-text type="info" tag="b">
                                    <TT>返回值 Return Value</TT> :
                                </el-text></el-col>
                                <el-col :span="6"> <el-text type="info">
                                    {{props.row.retVal}}
                                </el-text>
                                </el-col>

                                <el-col :span="4"> <el-text type="info" tag="b">
                                    <TT>nFolded</TT> :
                                </el-text></el-col>
                                <el-col :span="6"> <el-text type="info">
                                    {{props.row.nFolded}}
                                </el-text>
                                </el-col>
                            </el-row>


                            <el-row :gutter="20" class="d1">
                                <el-col :span="4"> <el-text type="info" tag="b">
                                    完整命令 <TT>fullCommand</TT>:
                                </el-text></el-col>
                                <el-col :span="12"> <el-text type="info"> <TT>{{props.row.argv0()}}</TT> </el-text> </el-col>
                            </el-row>

                            <el-row :gutter="20" class="d1">
                                <el-col :span="4">
                                    <el-text type="info" tag="b">
                                        <TT>argv</TT>:
                                    </el-text>
                                </el-col>
                                <el-col :span="12">
                                    <el-text type="info"> <TT>{{props.row.argv1()}}</TT> </el-text>
                                </el-col>
                            </el-row>

                            <el-row :gutter="20" class="d1">
                                <el-col :span="4">
                                    <el-text type="info" tag="b">
                                        <TT>记录储存对象 hashUri</TT>:
                                    </el-text>
                                </el-col>
                                <el-col :span="12">
                                    <el-text type="info"> <TT>{{props.row.hashUri}}</TT> </el-text>
                                </el-col>
                            </el-row>

                            <el-row :gutter="20" class="d1">
                                <el-col :span="4">
                                    <el-text type="info" tag="b">
                                        <TT>AI 审计分数 Suspiciousness </TT>:
                                    </el-text>
                                </el-col>
                                <el-col :span="12">
                                    <el-text type="info"> <TT>{{props.row.spsScore}}</TT> </el-text>
                                </el-col>
                            </el-row>

                            <el-row :gutter="20" class="d1">
                                <el-col :span="6">
                                    <el-text type="info" tag="b">
                                        <TT>AI 审计总结 Suspiciousness Reason </TT>:
                                    </el-text>
                                </el-col>
                                <el-col :span="15">
                                    <el-text type="info"> <TT>{{props.row.spsReason}}</TT> </el-text>
                                </el-col>
                            </el-row>

                        </div>
                    </div>
                </template>
            </el-table-column>


            <el-table-column label="ID" prop="id" width="50"> </el-table-column>
            <el-table-column label="用户 User" prop="user" width="80"> </el-table-column>
            <el-table-column label="命令 Cmd" prop="cmd" width="100">
                <template v-slot="{row}"> <TT>{{row.cmd.split('/').pop()}}</TT> </template>
            </el-table-column>
            <el-table-column label="命令参数 Argv" prop="argv">
                <template v-slot="{row}"> <TT>{{row.argv1()}}</TT> </template>
            </el-table-column>
            <el-table-column label="检测时间 Observation Time" prop="time" sortable="custom">
                <template v-slot="{row}"> {{parseTime(row.time, '{y}-{m}-{d} 星期{a} {h}:{i}:{s}')}} </template>
            </el-table-column>
            <el-table-column label="已存证 Chained" prop="chained">
                <template v-slot="{row}"> 
                    <span v-if="row.chained"> <el-tag type="success">Yes</el-tag> </span>
                    <span v-else> <el-tag type="danger">No</el-tag> </span>
                </template>
            </el-table-column>
            <el-table-column label="审计分数 Sps-Score" prop="spsScore" sortable="custom">
                <template v-slot="{row}"> <TT>{{row.spsScore}}</TT> </template>
            </el-table-column>
        </el-table>
        <!-- <LottieAnimation :animation-data="WatermelonJSON" class="anim" :auto-play="true" :loop="true" :speed="0.1" ref="anim" /> -->
        <!-- <LottieAnimation :animation-data="DrinkingJSON" class="anim1" :auto-play="true" :loop="true" :speed="1" ref="anim" /> -->
        <LottieAnimation :animation-data="ChillPeopleJSON" class="anim1" :auto-play="true" :loop="true" :speed="1" ref="anim" />


    <LottieAnimation :animation-data="R1JSON"
class="anim r1" :auto-play="true" :loop="true" :speed="0.05" ref="anim" />

    <LottieAnimation :animation-data="R2JSON" class="anim r2" :auto-play="true" :loop="true" :speed="0.02" ref="anim" />

    <LottieAnimation :animation-data="R3JSON" class="anim r3" :auto-play="true" :loop="true" :speed="0.05" ref="anim" />

    <pagination v-show="totalCount>0" :total="totalCount" v-model:page="listQuery.page" v-model:limit="listQuery.limit" @pagination="getList" />

    </div>
</template>

<script setup lang="ts">
 import { watch, ref, onMounted, defineComponent, markRaw } from 'vue';
 import { Search, Edit, Download, Calendar } from '@element-plus/icons-vue';
 import waves from '@/directive/waves'; // waves directive
 import { parseTime } from '@/utils';
 import Pagination from '@/components/Pagination'; // secondary package based on el-pagination
 import { fetchUsers, fetchCmds} from '@/api/hi_api';

 import { LottieAnimation } from "lottie-web-vue";
 import WatermelonJSON from "@/assets/watermelon.json";
 import ChillPeopleJSON from "@/assets/peopleChillChecking.json";
 import DrinkingJSON from "@/assets/drinking.json";

 import R1JSON from "@/assets/ShapesLoader.json";
 import R2JSON from "@/assets/ShapesLoader1.json";
 import R3JSON from "@/assets/CircularLoader.json";
 import {Tween, Easing} from '@tweenjs/tween.js';
 import {datetimeShortcuts} from '@/dt';
 // interface Cmd {id: number; user: string; cmd: string;
 //     argv: string; time: string; chained: boolean; tx_hash: string;
 // }

 const dateRange = ref<[Date, Date]>([
     new Date(0),// yesterday
     new Date(),// now
 ]);

 watch(dateRange, async (x) => {
     console.log('🦜: dateRange changed to:', x);
     listQuery.value.sinceTime = parseTime(x[0], '{y}-{m}-{d} {h}:{i}:{s}');
     listQuery.value.untilTime = parseTime(x[1], '{y}-{m}-{d} {h}:{i}:{s}');
     await handleFilter();
 });



 class Cmd {
     id: number;
     user: string | undefined
     cmd: string;
     argv: string[];
     time: Date;
     chained: boolean;
     tx_hash: string;
     pid: number;
     ppid: number;
     retVal: number;
     nFolded: number;
     registerTime: Date;

     hashUri: string;
     spsScore: number;// the score of the process being suspicious: 0 ~ 1
     spsReason: string;// the reason why it is suspicious

     constructor(id: number, uid: number, cmd: string, argv: string, time: number, tx_hash: string,
                 pid: number, ppid: number, retVal: number, nfolded: number,
                 registerTime: number, hashUri: string = '', spsScore: number = 0, spsReason: string = ''
     ) {
         this.id = id;
         this.user = uid2user.value ? uid2user.value.get(uid) : '';
         this.cmd = cmd;
         this.argv = argv.split(' ');
         this.time = new Date(time)
         this.registerTime = new Date(registerTime)
         this.chained = (tx_hash.length > 0);
         this.tx_hash = tx_hash;
         this.pid = pid; this.ppid = ppid; this.retVal = retVal;
         this.nFolded = nfolded;
         this.hashUri = hashUri;
         this.spsScore = spsScore;
         this.spsReason = spsReason;
      }

     argv1(): string{
         // argv[1:]
         return this.argv.slice(1).join(' ');
     }

     argv0(): string{
         // argv[0]: the full command
         return this.argv[0];
     }

 };

 let anim = ref();

 interface ListQuery {
     page: number; limit: number; user: string | undefined; uid: number | undefined;
     cmd: string | undefined; hash: string | undefined; sort: string;
     ascending: boolean;
 }

 interface RestaurantItem {value: string; link: string;}

 interface User {name: string; uidInt: number;}

 const iconSearch = markRaw(Search);
 const tableKey = ref(0);
 const list = ref<Cmd[]>([]);
 const listQuery = ref<ListQuery>(
     { page: 1, limit: 20, user: '', uid: 0, cmd: '', hash: '', sort: '', ascending: true }
 );

 const getList = async () => {
     // 🦜: fetch the list from the remote
     /*
        🦜: what we need
        list.value = [
        { id: 1, user: 'root', cmd: '/usr/local/bin/ls', argv: '/usr/bin', time: '2024-11-12 11:11:11', chained: false, tx_hash: '' },
        { id: 2, user: 'root', cmd: 'cat', argv: '/etc/pswd', time: '2024-11-12 11:11:11', chained: true, tx_hash: '123' },
        { id: 3, user: 'root', cmd: 'cat', argv: '/etc/pswd', time: '2024-11-12 11:11:11', chained: true, tx_hash: '123' },
        { id: 4, user: 'me', cmd: '/usr/local/bin/ls', argv: '/usr/Music/hi.txt', time: '2024-11-12 11:11:11', chained: false, tx_hash: '' },
        { id: 5, user: 'me', cmd: '/usr/local/bin/cat', argv: '/usr/Music/ho.txt', time: '2024-11-12 11:11:12', chained: false, tx_hash: '' },
        ];
        totalPage.value = 1;
      */

     // 0. give lq the valid uid
     let lq = listQuery.value;
     if (lq.user && lq.user.length === 0) {
         lq.uid = undefined;
     }else if (!user2uid.value || !lq.user){
         lq.uid = undefined;
     } else {
         if (! user2uid.value.has(lq.user)){
             ElMessage({message: '这个user不认识', type: 'error'});
             return new Promise((Y,N) => {N('这个user不认识')})
         }
         lq.uid = user2uid.value.get(lq.user);
     }

     // 1. fetch
     let o = await fetchCmds(lq);
     // 1.1 🦜 : the code check is in utils/request.js
     console.log('🦜 : fetched cmds:', o);

     // 2. make it clean for our usage, in particular:
     /*
        2.1. convert its time (in unix epoch) to Date
        2.2 if it has a hash, then it is chained
      */
     o = o['data']
     let vl = o['voList']
     vl = vl.map((c: any) => {
         return new Cmd(c.id, c.uid, c.cmd, c.argv, c.time, c.hash, c.pid,
                        c.ppid, c.retVal, c.nfolded, c.registerTime,
                        c.hashUri, c.spsScore, c.spsReason
         );
     });

      // 3. set the list
     list.value = vl;
     // 4. set the total Pages
     totalPage.value = o['totalPages'];
     totalCount.value = o['totalCount'];
 }

 const handleFilter = async () => {
     console.log(`🦜 : handleFilter() with `, listQuery.value);
     await getList();
 };

 const totalPage = ref(1);
 const totalCount = ref(1);
 const users = ref<User[] | null>(null);

 const listLoading = ref(false);
 const user2uid = ref<Map<string, number> | null>(null);
 const uid2user = ref<Map<number, string> | null>(null);

 onMounted(async () => {
     listLoading.value = true;
     let response = await fetchUsers();
     users.value = response.data;

     listLoading.value = false;

     users.value as User[]
     if (users.value !== null){
         user2uid.value = new Map(users.value.map((u: User) => [u.name, u.uidInt]));
         uid2user.value = new Map(users.value.map((u: User) => [u.uidInt, u.name]));

         console.log(`🦜 : table created and got ${users.value.length} users, user2uid:`, user2uid.value);
         // console.log(`🦜 : uid2user:`, this.uid2user);
         await getList();
     }else{
         ElMessage({message: "🦜: Error getting users", type: 'error'});
     }

     // our animation
     setTimeout(() => {
         console.log(anim.value.goToAndPlay(150, true));
         anim.value;
    }, 500);


     // r1's rotation
     // --------------------------------------------------
     const ar1 = document.querySelector('.anim.r1');
     const ar2 = document.querySelector('.anim.r2');
     const ar3 = document.querySelector('.anim.r3');
     // const ar4 = document.querySelector('.anim.r4');
     // console.log('🦜: ar1', ar1);
     // rotate the .anim.r1's rotation
     const tween = new Tween({rotation: 0})
         .to({rotation: 360}, 200000)
         .onUpdate((obj) => {
             let r = obj.rotation;
             ar1.style.transform = `rotate(${r}deg)`;
             ar2.style.transform = `rotate(${r}deg)`;
             ar3.style.transform = `rotate(${r}deg)`;
             // ar4.style.transform = `rotate(${r}deg)`;
         })
         .repeat(Infinity)
         .start();


     function update(time) {
         requestAnimationFrame(update);
         tween.update(time);
     }
     requestAnimationFrame(update);

 });

 const handleSelect = (item: RestaurantItem) => {
     console.log(`🦜 selected user = `, item); // 🦜 : nothing to be done here....
 };

 const querySearch = (queryString: string, cb: any) => {
     const l = users.value;
     let r = queryString ? l.filter(
         (u: User) => u.name.toLowerCase().includes(queryString.toLowerCase())
     ) : l;
     r = r.map((u: User) => ({ value: u.name }));
     // an array of {value}
     // call callback function to return suggestions
     cb(r);
 };

 const sortChange = async (data: any) => {
     const { prop, order } = data;
     console.log('🦜 : sortChange ->', prop, order);
     listQuery.value.ascending = order === 'ascending';
     if (order == null) {
         listQuery.value.sort = "";
     } else {
         listQuery.value.sort = prop;
         console.assert((prop === 'time') ||
                        (prop === 'spsScore')
                        , '❌️ : prop should be time');
     }
     await getList();
 };


 const rowClassName = ({ row, rowIndex }: { row: Cmd, rowIndex: number }) => {
     return '';
     // 🦜 : Okay... coloring the row based on status <2024-11-12 Tue> doesn't look quite nice....
 };


 const getSortClass = (key: string) => {
     const sort = listQuery.value.sort;
     return sort === `+${key}` ? 'ascending' : 'descending';
 };
</script>

<style lang="scss">
 @use 'base'
</style>
